package com.pn.taikao.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import com.pn.taikao.service.CaptchaService;
import org.springframework.stereotype.Service;

import java.awt.image.BufferedImage;
import java.time.Instant;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 验证码服务实现（内存存储版）
 * 不依赖 Redis，支持前端“点图换一张”直接获取新的验证码
 */
@Service
public class CaptchaServiceImpl implements CaptchaService {

    private static final int CAPTCHA_EXPIRE_SECONDS = 300; // 5分钟

    // 内存缓存：captchaKey -> Entry(codeLowerCase, expiresAtEpochSeconds)
    private final Map<String, Entry> captchaCache = new ConcurrentHashMap<>();

    public CaptchaServiceImpl() {}

    @Override
    public BufferedImage generateCaptchaImage(String captchaKey) {
        // 生成图形验证码（圆圈干扰）: 宽110，高40，字符数4，干扰元素20
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(110, 40, 4, 20);

        String captchaText = captcha.getCode();

        // 写入内存缓存，大小写不敏感，统一转小写
        long expiresAt = Instant.now().getEpochSecond() + CAPTCHA_EXPIRE_SECONDS;
        captchaCache.put(captchaKey, new Entry(captchaText.toLowerCase(), expiresAt));

        // 返回验证码图片
        return captcha.getImage();
    }

    @Override
    public boolean validateCaptcha(String captchaKey, String captchaCode) {
        if (captchaKey == null || captchaCode == null || captchaCode.trim().isEmpty()) {
            return false;
        }

        Entry entry = captchaCache.get(captchaKey);
        if (entry == null) {
            return false; // 不存在或已被清理
        }

        // 过期校验
        long now = Instant.now().getEpochSecond();
        if (entry.expiresAtEpochSeconds < now) {
            captchaCache.remove(captchaKey);
            return false;
        }

        boolean ok = Objects.equals(entry.codeLowerCase, captchaCode.trim().toLowerCase());
        if (ok) {
            // 一次性使用，验证成功后移除
            captchaCache.remove(captchaKey);
        }
        return ok;
    }

    private static final class Entry {
        final String codeLowerCase;
        final long expiresAtEpochSeconds;

        private Entry(String codeLowerCase, long expiresAtEpochSeconds) {
            this.codeLowerCase = codeLowerCase;
            this.expiresAtEpochSeconds = expiresAtEpochSeconds;
        }
    }
}

